using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace ExtendedDotNET.Controls.TransparentLabel
{
	/// <summary>
	/// Summary description for TransparentLabel.
	/// </summary>
	public class TransparentLabel : Control
	{
		ContentAlignment _textAlign = ContentAlignment.TopLeft ;
	    readonly StringFormat _drawFormat = new StringFormat(  ) ;
		Rectangle _textRect = new Rectangle( 0, 0, 0, 0 ) ;

		/// <summary> 
		/// Required designer variable.
		/// </summary>
#pragma warning disable 649
		private readonly Container _components;
#pragma warning restore 649

		public TransparentLabel()
		{
			// This call is required by the Windows.Forms Form Designer.
			InitializeComponent();
			SetStyle( ControlStyles.Opaque, false ) ;
			SetStyle( ControlStyles.ResizeRedraw, true ) ;
		}

		protected virtual void InvalidateEx( )
		{
			if ( null == Parent ) return ;
			var dirtyRect = new Rectangle( Location, Size ) ;
			Parent.Invalidate( dirtyRect, true ) ;
		}

		private void ResetAlign( )
		{
			switch ( _textAlign )
			{
				case ContentAlignment.BottomLeft:
				case ContentAlignment.MiddleLeft:
				case ContentAlignment.TopLeft:
					_drawFormat.Alignment = StringAlignment.Near ;
					break ;
				case ContentAlignment.BottomCenter:
				case ContentAlignment.MiddleCenter:
				case ContentAlignment.TopCenter:
					_drawFormat.Alignment = StringAlignment.Center ;
					break ;
				case ContentAlignment.BottomRight:
				case ContentAlignment.MiddleRight:
				case ContentAlignment.TopRight:
					_drawFormat.Alignment = StringAlignment.Far ;
					break ;
			}
		}

		private void ResetRect( )
		{
			Graphics g = CreateGraphics( ) ;
			SizeF textSize = g.MeasureString( base.Text, Font ) ;
			switch ( _textAlign )
			{
				case ContentAlignment.BottomLeft:
				case ContentAlignment.BottomCenter:
				case ContentAlignment.BottomRight:
					_textRect = new Rectangle( 0, ClientRectangle.Height - (int)textSize.Height, ClientRectangle.Width, (int)textSize.Height ) ;
					break ;
				case ContentAlignment.MiddleLeft:
				case ContentAlignment.MiddleCenter:
				case ContentAlignment.MiddleRight:
					_textRect = new Rectangle( 0, ((ClientRectangle.Height - (int)textSize.Height) / 2), ClientRectangle.Width, (int)textSize.Height ) ;
					break ;
				case ContentAlignment.TopLeft:
				case ContentAlignment.TopCenter:
				case ContentAlignment.TopRight:
					_textRect = new Rectangle( 0, 0, ClientRectangle.Width, (int)textSize.Height ) ;
					break ;
			}
			g.Dispose( ) ;
		}

		#region Overrides.

		protected override CreateParams CreateParams
		{
			get
			{
				CreateParams cp = base.CreateParams ;
				cp.ExStyle |= 0x00000020 ; //WS_EX_TRANSPARENT
				return( cp ) ;
			}
		}

		protected override void InitLayout()
		{
			base.InitLayout( ) ;
			ResetAlign( ) ;
			ResetRect( ) ;
			// This get's removed immediatly upon the first invocation.
			Parent.Paint += (OnParentPaint);
		}

		//Must be stubbed out. If you implement this you will loose your transparent background.
		protected override void OnPaintBackground(PaintEventArgs pevent) 
		{ 
			//do not allow the background to be painted  
			//Debug.WriteLine( "TransparentLabel(" + this.Name + ")::OnPaintBackground" ) ;
		}

		protected override void OnResize(EventArgs e)
		{
			base.OnResize (e);
			ResetRect( ) ;
		}

		protected override void OnPaint(PaintEventArgs e)
		{
			Graphics g = e.Graphics ;
			Color fg = ForeColor ;
			if ( ! Enabled ) fg = SystemColors.GrayText ;
			var drawBrush = new SolidBrush( fg ) ;
			g.DrawString( base.Text, Font, drawBrush, _textRect, _drawFormat ) ;
			drawBrush.Dispose( ) ;
		}

		protected override void OnEnabledChanged(EventArgs e)
		{
			base.OnEnabledChanged (e);
			InvalidateEx( ) ;
			Invalidate( ) ;
		}

		protected override void OnFontChanged(EventArgs e)
		{
			base.OnFontChanged (e);
			ResetRect( ) ;
			InvalidateEx( ) ;
			Invalidate( ) ;
		}

		protected override void OnParentChanged(EventArgs e)
		{
			base.OnParentChanged (e);
			InvalidateEx( ) ;
			Invalidate( ) ;
		}

		protected override void OnVisibleChanged(EventArgs e)
		{
			base.OnVisibleChanged (e);
			InvalidateEx( ) ;
			Invalidate( ) ;
		}

		protected override void OnTextChanged(EventArgs e)
		{
			base.OnTextChanged (e);
			ResetRect( ) ;
			InvalidateEx( ) ;
			Invalidate( ) ;
		}

		protected override void OnLocationChanged(EventArgs e)
		{
			base.OnLocationChanged (e);
			InvalidateEx( ) ;
			Invalidate( ) ;
		}

		/// <summary> 
		/// Clean up any resources being used.
		/// </summary>
		protected override void Dispose( bool disposing )
		{
			if( disposing )
			{
				if(_components != null)
				{
					_components.Dispose();
				}
				_drawFormat.Dispose( ) ;
			}
			base.Dispose( disposing );
		}

		#endregion

		#region Component Designer generated code.

		/// <summary> 
		/// Required method for Designer support - do not modify 
		/// the contents of this method with the code editor.
		/// </summary>
		private void InitializeComponent()
		{
			// 
			// TransparentLabel
			// 
			BackColor = SystemColors.Control;
			Name = "TransparentLabel";
			Size = new Size(192, 16);

		}

		#endregion

		#region Properties.

		[Browsable( true ),
		DesignerSerializationVisibility( DesignerSerializationVisibility.Visible )]
		public override string Text
		{
			get { return base.Text ; }
			set { base.Text = value; InvalidateEx( ) ; }
		}

		[Browsable( true ),
		DesignerSerializationVisibility( DesignerSerializationVisibility.Visible ),
		DefaultValue(ContentAlignment.TopLeft)]
		public ContentAlignment TextAlign
		{
			get { return( _textAlign ) ; }
			set
			{
				_textAlign = value ;
				InvalidateEx( ) ;
				ResetAlign( ) ;
				ResetRect( ) ;
			}
		}

		#endregion

		#region Event Handlers.

		private void OnParentPaint(object sender, PaintEventArgs e)
		{
			Invalidate( ) ;
			// This get's removed immediatly upon the first invocation, 
			// becuase it is just a cludge to stop the text from disapearing when
			// you drop a TranparentLable onto a container.
			// If you don't remove it you get way-to-many paints.
            if(Parent != null)
			Parent.Paint -= (OnParentPaint);
		}
		
        #endregion
	}
}
